/*
 * @Description:
 * @Author: fhw
 * @Date: 2022-12-29 16:54:38
 */
import {
	computed,
	createVNode,
	defineComponent,
	inject,
	nextTick,
	onMounted,
	onUnmounted,
	reactive,
	Ref,
	ref,
	watch,
} from 'vue'
import { PlusOutlined, EllipsisOutlined, ExclamationCircleOutlined, SearchOutlined } from '@ant-design/icons-vue'
import { clone, equals, head, isEmpty, isNil, map, uniqWith } from 'ramda'
import { FormTextArea, FormFollow, FormSearch, Scroll } from '@/components'
import UserInfo from '@/components/user/userInfo'
import './style.scss'
import { ChatRecord, HistorySession, User } from '@/interface'
import { isTrue } from '@/utils/tools'
import { errorTips, formatTime, random, searchFilter, successTips } from '@/utils'
import * as IndexedDB from '@/indexedDB'
import { DrawerState, UserInfoModalState } from './interface'
import { Socket } from 'socket.io-client'
import { BasicDataModule } from '@/store/modules/basicData'
import { ContextmenuItem } from '@/components/Contextmenu/interface'
import { Modal } from 'ant-design-vue'
import dayjs from 'dayjs'
import { msgTimeFormat } from './common'
import UserImg from '@/components/user/userImg'
import { textReplaceEmoji } from '@/utils/emojis'
import CreateGroupChat from './components/createGroupChat'
import { GroupChatRecord } from '@/interface/chat'
import { IconCloseChime } from '@/components/icon'
import { useRoute } from 'vue-router'
const $styles = {
	searchIconSize: '17px',
}
export function toScrollBottom() {
	setTimeout(() => {
		const message = document.querySelector('.chat-box')?.querySelector('.mia-scroll-box') as HTMLElement
		if (!message) return
		message.scrollTop = message.scrollHeight + 999999999999999
	}, 10)
}
export default defineComponent({
	name: 'Index',
	setup() {
		const route = useRoute()
		onMounted(() => {
			nextTick(() => {
				toScrollBottom()
			})
			// 获取历史会话
			if (!isTrue(BasicDataModule.historySession)) {
				BasicDataModule.getHistorySession()
			}
		})
		// 历史会话
		const historySession = ref<HistorySession[]>([])
		watch(
			() => BasicDataModule.historySession,
			() => {
				if (isTrue(BasicDataModule.historySession)) {
					if (route.query.userId) {
						openChat(route.query.userId)
					}
					historySession.value = BasicDataModule.historySession
				}
			},
			{
				immediate: true,
				deep: true,
			}
		)
		// 好友备注集合
		const friendsRemarksMap = computed<Map<string, string>>(() => {
			return BasicDataModule.friendsRemarksMap
		})
		// 用户信息
		const userInfo = computed(() => {
			return BasicDataModule.userInfo
		})
		// 通讯
		const socket = inject('socket') as Socket
		const chatRef = ref<any>()
		const pageState = reactive({
			pageNum: 2,
			pageSize: 20,
			total: 9999,
			loading: false,
		})
		const chatState = reactive({ content: '' })
		const userId = localStorage.getItem('userId') as string
		// 联系人
		// 将用户放置仓库，在仓库中使用，接受数据时阻止消息回显
		const historySessionInfo = ref<HistorySession>()
		// 聊天记录
		const chatRecord = ref<ChatRecord[]>([])

		watch(
			() => route.query.userId,
			(id) => {
				if (!id) return
				openChat(id)
			},
			{
				immediate: true,
			}
		)
		function openChat(id: any) {
			const data = BasicDataModule.historySession.find((item) => equals(item.historicalUserSessionsId, id))
			if (data) {
				nextTick(() => {
					getIndexedDBCommunication(data)
				})
			}
		}
		/**
		 * 获取IndexedDB聊天记录
		 * @param {HistorySession} item
		 */
		async function getIndexedDBCommunication(item: HistorySession) {
			// 重置分页数
			pageState.pageNum = 2
			chatRecord.value = []
			historySessionInfo.value = clone(item)
			try {
				// 读取IndexedDB数据库数据
				const userChatRecordReadAll = await IndexedDB.readAll(`user-chat-record-${item.historicalUserSessionsId}`)
				chatRecord.value = clone(userChatRecordReadAll as ChatRecord[]) ?? []
				toScrollBottom()
				updateChatUnreadMessage()
				if (isEmpty(userChatRecordReadAll)) {
					pageState.pageNum = 1
					getChatCommunication()
				}
			} catch (error) {
				const tableList = [
					{
						// 表名
						tableName: `user-chat-record-${item.historicalUserSessionsId}`,
						// 主键
						keyPath: 'id',
						autoIncrement: true,
					},
				]
				IndexedDB.init('chat', tableList)
				pageState.pageNum = 1
				getChatCommunication()
			}
		}
		// 获取聊天记录并写入indexedDB数据库
		async function getChatCommunication(miaScroll?: Ref<HTMLElement>) {
			if (!isTrue(historySessionInfo.value)) return
			if (chatRecord.value.length > pageState.total) return
			if (pageState.loading) return
			const scrollHeight = miaScroll?.value.scrollHeight
			const historicalUserSessionsId = historySessionInfo.value?.historicalUserSessionsId
			const parmas: API.blog.chatRecord.getUserChatRecord.Params = {
				userId: Number(userId),
				to_userId: historicalUserSessionsId,
				pageSize: pageState.pageSize,
				pageNum: pageState.pageNum,
				group_id: undefined,
			}
			// 获取群聊聊天记录
			if (!isNil(historySessionInfo.value?.chatUserGroup)) {
				parmas.to_userId = undefined
				parmas.group_id = historicalUserSessionsId
			}
			pageState.loading = true
			const { success, data } = await API.blog.chatRecord.getUserChatRecord.request(parmas)
			pageState.loading = false
			if (success && isTrue(data.data)) {
				const record = (data.data as ChatRecord[]).concat(chatRecord.value)
				if (equals(historySessionInfo.value?.historicalUserSessionsId, historicalUserSessionsId)) {
					chatRecord.value = record
				}
				updateChatUnreadMessage()
				pageState.total = data.total
				pageState.pageNum++
				const userChatRecordReadAll = await IndexedDB.readAll(`user-chat-record-${historicalUserSessionsId}`)

				if (historySessionInfo.value?.historicalUserSessionsId && isEmpty(userChatRecordReadAll)) {
					record.forEach((item) => {
						IndexedDB.add<ChatRecord>(
							`user-chat-record-${historySessionInfo.value?.historicalUserSessionsId}`,
							clone(item)
						)
					})
				}

				if (miaScroll) {
					nextTick(() => {
						// 固定在触顶位置
						miaScroll.value.scrollTop = miaScroll?.value.scrollHeight - (scrollHeight ?? 0)
					})
				} else {
					nextTick(() => {
						toScrollBottom()
					})
				}
			}
		}
		// 抽屉状态数据
		const drawerState = reactive<DrawerState>({
			visible: false,
			data: [],
			historySessionInfo: {},
			openCreateGroupChatVisible: false,
		})
		// 打开抽屉
		function openDrawer() {
			drawerState.visible = true
			drawerState.historySessionInfo = historySessionInfo.value as HistorySession
			// 好友
			if (isTrue(historySessionInfo.value?.friends)) {
				drawerState.data = [clone(historySessionInfo.value?.friends as User)]
			}
			// 群聊
			if (isTrue(historySessionInfo.value?.chatUserGroup)) {
				drawerState.data = clone(historySessionInfo.value?.chatUserGroup?.groupMembers as User[])
			}
		}
		const userInfoModalState = reactive<UserInfoModalState>({
			visible: false,
			loading: false,
			user: {} as User,
		})
		// 打开用户详情
		async function openUserInfo(friendsId: number) {
			userInfoModalState.visible = true
			if (equals(userInfoModalState.user.id, friendsId)) return
			if (equals(friendsId, Number(userId))) {
				getUserInfo()
				return
			}
			userInfoModalState.loading = true
			const { success, data }: { success: boolean; data: User } = await API.blog.chatUser.getUserInfo.request({
				id: friendsId,
			})
			userInfoModalState.loading = false
			if (!success) return
			userInfoModalState.user = {
				id: data.id,
				username: data.username,
				account: data.account,
				sex: data.sex,
				age: data.age,
				headimgurl: data.headimgurl,
			}
		}
		// 获取用户详情
		function getUserInfo() {
			userInfoModalState.user = {
				id: userInfo?.value.id,
				username: userInfo?.value.username,
				account: userInfo?.value.account,
				sex: userInfo?.value.sex,
				age: userInfo?.value.age,
				headimgurl: userInfo?.value.headimgurl,
				remarks: userInfo?.value.remarks,
			}
		}
		/** 聊天记录触顶 */
		async function onScroll(miaScroll: Ref<HTMLElement>) {
			const scrollTop = miaScroll.value?.scrollTop
			const userChatRecordReadAll = await IndexedDB.readAll(
				`user-chat-record-${historySessionInfo.value?.historicalUserSessionsId}`
			)
			if (isEmpty(userChatRecordReadAll)) {
				pageState.pageNum = 1
			}
			if (equals(scrollTop, 0)) {
				getChatCommunication(miaScroll)
			}
		}
		/** 消息发送 */
		async function onChatSend() {
			if (!isTrue(chatState.content)) return
			let sendObjs: ChatRecord | GroupChatRecord = {}
			if (isNil(historySessionInfo.value?.chatUserGroup)) {
				sendObjs = {
					userId: userInfo?.value.id as number,
					username: userInfo?.value.username,
					to_userId: historySessionInfo.value?.historicalUserSessionsId,
					to_username: historySessionInfo.value?.friends?.username,
					content: chatState.content,
					type: 1,
					classType: 1,
					createDate: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'),
					id: random(90000, 10000000),
				}
				socket?.emit('sendChat', sendObjs)
				chatRecord.value.push(sendObjs)
			} else {
				sendObjs = {
					group_id: historySessionInfo.value?.historicalUserSessionsId,
					userId: userInfo?.value.id as number,
					content: chatState.content,
					type: 1,
					classType: 2,
					createDate: dayjs(new Date()).format('YYYY-MM-DD HH:mm:ss'),
					id: random(90000, 10000000),
				}
				socket?.emit('groupChatMessage', sendObjs)
			}
			chatState.content = ''
			// 更新最新消息
			BasicDataModule.updateLatestNews(sendObjs)
			nextTick(() => {
				toScrollBottom()
			})
			updateIndexedDBData(sendObjs)
		}
		/**
		 * 更新消息已读
		 */
		async function updateChatUnreadMessage() {
			const ids = chatRecord.value.filter((item) => equals(item.isRead, 0)).map((item) => item.id)
			const userChatRecordReadAll = (await IndexedDB.readAll(
				`user-chat-record-${historySessionInfo.value?.historicalUserSessionsId}`
			)) as ChatRecord[]
			// 更新数据库未读消息
			userChatRecordReadAll.forEach((item) => {
				if (ids.includes(item.id)) {
					item.isRead = 1
					IndexedDB.add<ChatRecord>(
						`user-chat-record-${historySessionInfo.value?.historicalUserSessionsId}`,
						clone(item)
					)
				}
			})
			chatRecord.value.forEach((item) => {
				if (ids.includes(item.id)) {
					item.isRead = 1
				}
			})
			if (!isTrue(historySessionInfo.value?.groupChat)) {
				socket.emit('updateUnreadMessage', { ids, userId })
			} else {
				socket.emit('updateUnreadMessage', { userId, group_id: historySessionInfo.value?.historicalUserSessionsId })
			}
		}
		// 监听数据，并更新已读消息
		socket.on('acceptChat', acceptChat)
		socket.on('acceptGroupChatMessage', acceptChat)
		// 页面卸载删除acceptChat监听
		onUnmounted(() => {
			socket.removeListener('acceptChat', acceptChat)
			socket.removeListener('acceptGroupChatMessage', acceptChat)
		})
		function acceptChat(data: ChatRecord) {
			const historicalUserSessionsId = historySessionInfo.value?.historicalUserSessionsId
			// 判断是否发送给自己数据，只针对单个聊天
			const isUserId = equals(String(data.to_userId), userId)
			// 判断选中用户
			const isHSId = isTrue(data.groupChat)
				? equals(data.group_id, historicalUserSessionsId)
				: equals(String(data.userId), historicalUserSessionsId)
			const so = isTrue(data.groupChat) ? isHSId : isUserId && isHSId
			if (so) {
				chatRecord.value.push(data)
				nextTick(() => {
					toScrollBottom()
				})
				updateChatUnreadMessage()
			}
		}
		/**
		 * 更新数据库
		 * @param data 聊天记录
		 */
		async function updateIndexedDBData(data: ChatRecord | GroupChatRecord) {
			const historicalUserSessionsId = historySessionInfo.value?.historicalUserSessionsId
			const userChatRecordReadAll = (await IndexedDB.readAll(
				`user-chat-record-${historicalUserSessionsId}`
			)) as ChatRecord[]
			if (isTrue(userChatRecordReadAll)) {
				await IndexedDB.remove({
					tableName: `user-chat-record-${historicalUserSessionsId}`,
					key: head(userChatRecordReadAll)?.id as number,
				})
			}
			await IndexedDB.add<ChatRecord | GroupChatRecord>(`user-chat-record-${historicalUserSessionsId}`, clone(data))
		}
		/** 删除聊天用户 */
		function deleteHistorySession(e: any) {
			Modal.confirm({
				title: '确定删除该聊天用户吗？',
				icon: () => createVNode(ExclamationCircleOutlined),
				okText: '确认',
				cancelText: '取消',
				onOk: async () => {
					const index = e.getAttribute('data-index')
					const { userId, id, historicalUserSessionsId } = historySession.value[index]
					const { success } = await API.blog.historySession.deleteHistorySession.request({
						userId,
						id,
						historicalUserSessionsId,
					})
					if (success) {
						historySessionInfo.value = undefined
						// 清空index文件中的数据
						historySession.value.splice(index, 1)
					}
				},
			})
		}
		/** 设置消息免打扰 */
		async function updateDoNotDisturb(e: { getAttribute: (arg0: string) => any }) {
			const index = e.getAttribute('data-index')
			handleDoNotDisturb(index)
		}
		async function handleDoNotDisturb(index: number) {
			const { userId, doNotDisturb, historicalUserSessionsId } = historySession.value[index]
			const { success, data, msg } = await API.blog.historySession.updateDoNotDisturb.request({
				userId,
				doNotDisturb: equals(doNotDisturb, 1) ? '0' : '1',
				historicalUserSessionsId,
			})
			success ? successTips(data) : errorTips(msg)
			if (success) {
				historySession.value[index].doNotDisturb = equals(doNotDisturb, 1) ? 0 : 1
			}
		}
		const userListmenus = (e: { getAttribute: (arg0: string) => any }): ContextmenuItem[] => {
			const index = e.getAttribute('data-index')
			const doNotDisturb = historySession.value[index].doNotDisturb
			return [
				{
					text: '置顶',
				},
				{
					text: '标记已读',
				},
				{
					text: equals(String(doNotDisturb), '1') ? '消息免打扰' : '开启新消息提示',
					handler: updateDoNotDisturb,
				},
				{
					text: '删除聊天',
					handler: deleteHistorySession,
				},
			]
		}
		const records = computed(() => {
			const data = uniqWith((a, b) => a.id == b.id, chatRecord.value ?? []).sort(
				(a, b) => (new Date(a.createDate as string) as any) - (new Date(b.createDate as string) as any)
			)
			return msgTimeFormat(data, 0, 0)
		})
		watch(
			() => BasicDataModule.contacts,
			(contacts) => {
				if (!isEmpty(contacts)) {
					const userId = localStorage.getItem('userId') as string
					// 注册群聊
					contacts.forEach((item) => {
						if (equals(item.classType, 2)) {
							socket?.emit('groupChatLogin', { group_id: item.group_id, userId })
						}
					})
				}
			},
			{
				deep: true,
				immediate: true,
			}
		)
		function messageWrapperRender(data: ChatRecord) {
			return !equals(data.userId as number, Number(userId)) ? (
				<div class="msg msg-left">
					<div class="img-wrapper" onClick={() => openUserInfo(data.userId as number)}>
						<UserImg iconSize={36} imgSize={36} headimgurl={data.user?.headimgurl} />
					</div>
					<div class="msg-left-box">
						<div class="name">{friendsRemarksMap.value.get(String(data.userId)) ?? data.user?.username}</div>
						<div class="message-box">
							<div class="message-wrapper message-wrapper-left">
								<div class="message" v-html={textReplaceEmoji(data.content as string)}></div>
							</div>
							{/* <div class="isRead">{equals(data.isRead, 1) ? '已读' : '未读'}</div> */}
						</div>
					</div>
				</div>
			) : (
				<div class="msg msg-right">
					<div class="img-wrapper" onClick={() => openUserInfo(data.userId as number)}>
						<UserImg iconSize={36} imgSize={36} headimgurl={userInfo?.value.headimgurl} />
					</div>
					<div class="message-wrapper message-wrapper-right">
						<div class="message" v-html={textReplaceEmoji(data.content as string)}></div>
					</div>
				</div>
			)
		}

		return () => (
			<div class="chat-window">
				<div class="chat-window-left">
					<FormSearch
						prefixIcon={<SearchOutlined style={{ fontSize: $styles.searchIconSize }} />}
						onChange={(value: string) => {
							if (!isTrue(value)) {
								historySession.value = BasicDataModule.historySession
							} else {
								historySession.value = searchFilter(BasicDataModule.historySession, value)
							}
						}}
					/>
					{/* 联系人 */}
					<Scroll height="calc(100% - 50px)">
						<ul>
							{historySession.value
								.sort(
									(a, b) =>
										(new Date(b.latestNews?.createDate as string) as any) -
										(new Date(a.latestNews?.createDate as string) as any)
								)
								.map((item, index) => {
									return (
										<li
											v-contextmenu={userListmenus}
											onClick={() => {
												if (equals(historySessionInfo.value?.id, item.id)) return
												getIndexedDBCommunication(item)
											}}
											data-index={index}
											class={
												equals(historySessionInfo.value?.historicalUserSessionsId, item.historicalUserSessionsId)
													? 'active'
													: ''
											}
										>
											<div class="headimgurl">
												<UserImg iconSize={47} imgSize={47} headimgurl={item.friends?.headimgurl} />
												<a-badge
													count={BasicDataModule.chatUnreadMessage[item.historicalUserSessionsId as string]?.count ?? 0}
													dot={equals(item.doNotDisturb, 0)}
													style={
														equals(item.doNotDisturb, 0) ? { width: '10px', height: '10px', top: 0, right: 0 } : {}
													}
												/>
											</div>
											<div class="contacts-box">
												<div class="contacts-info">
													<div class="name one-hidden">
														{friendsRemarksMap.value.get(String(item.historicalUserSessionsId)) ??
															item.friends?.username ??
															item.groupChat?.groupChatName}
													</div>
													<div class="date">
														{item.latestNews?.createDate && formatTime(item.latestNews?.createDate as string)}
													</div>
												</div>
												{isTrue(item.latestNews) && (
													<div class="news-box">
														<div
															v-html={`
													${
														isTrue(item.groupChat) && isTrue(item.latestNews?.user)
															? (friendsRemarksMap.value.get(String(item.latestNews?.user?.id)) ??
																	item.latestNews?.user?.username) + '：'
															: ''
													}${item.latestNews?.content}
													`}
															class="message one-hidden"
														></div>
														{equals(item.doNotDisturb, 0) && <IconCloseChime fontSize={14} />}
													</div>
												)}
											</div>
										</li>
									)
								})}
						</ul>
					</Scroll>
				</div>
				<div class="chat-window-right">
					{isTrue(historySessionInfo.value) && (
						<>
							<div class="contact-header">
								<div class="name" onClick={openDrawer}>
									{friendsRemarksMap.value.get(String(historySessionInfo.value?.historicalUserSessionsId)) ??
										historySessionInfo.value?.friends?.username ??
										historySessionInfo.value?.groupChat?.groupChatName}
								</div>
								<EllipsisOutlined style={{ fontSize: '30px', cursor: 'pointer' }} onClick={openDrawer} />
							</div>
							<div class="dialog-box">
								<Scroll class="chat-box" ref={chatRef} onScroll={onScroll}>
									<div style="text-align: center;padding: 10px 0;">{pageState.loading && <a-spin />}</div>
									{records.value?.map((item) => {
										return (
											<div key={item.createDate as string}>
												{item?.isCompare ? (
													<div class="dataTime">
														<span>{item.content}</span>
													</div>
												) : (
													messageWrapperRender(item)
												)}
											</div>
										)
									})}
								</Scroll>

								<div class="input-box">
									<FormTextArea showEmotion onSend={onChatSend} v-model={[chatState.content, 'content']} />
								</div>
							</div>
						</>
					)}
				</div>
				<a-drawer placement="right" closable={false} v-model={[drawerState.visible, 'visible']}>
					<div class="drawer-box">
						<ul class="user-list">
							{map((item) => {
								return (
									<li onClick={() => openUserInfo(item.id as number)}>
										<UserImg iconSize={40} imgSize={40} headimgurl={item.headimgurl} />
										<p class="name one-hidden">{friendsRemarksMap.value.get(String(item.id)) ?? item?.username}</p>
									</li>
								)
							}, drawerState.data)}

							<li
								onClick={() => {
									drawerState.openCreateGroupChatVisible = true
								}}
							>
								<a-button icon={<PlusOutlined style={{ fontSize: '26px' }} />}></a-button>
								<p>添加</p>
							</li>
						</ul>
						<ul class="configure">
							<li>
								<p>消息免打扰</p>
								<a-switch
									checkedValue={0}
									unCheckedValue={1}
									v-model={[drawerState.historySessionInfo.doNotDisturb, 'checked']}
									onClick={() => {
										const index = historySession.value.findIndex(
											(item) => item.id === drawerState.historySessionInfo.id
										)
										if (equals(index, -1)) return
										handleDoNotDisturb(index)
									}}
								/>
							</li>
						</ul>
						<ul class="operation">
							<li>清空聊天记录</li>
						</ul>
					</div>
				</a-drawer>
				<FormFollow
					v-model={[userInfoModalState.visible, 'visible']}
					onCancel={() => {
						userInfoModalState.user = {}
					}}
				>
					<UserInfo
						dataSource={userInfoModalState.user}
						v-model={[userInfoModalState.loading, 'loading']}
						showRemarks={true}
					/>
				</FormFollow>
				<CreateGroupChat
					visible={drawerState.openCreateGroupChatVisible}
					data={drawerState.data}
					onCancel={() => {
						drawerState.openCreateGroupChatVisible = false
					}}
				/>
			</div>
		)
	},
})
